package com.teamone.mobilewatch.accessor.webservice;

import java.util.ArrayList;
import java.util.HashMap;

import android.util.Log;

import com.teamone.mobilewatch.accessor.BackendException;
import com.teamone.mobilewatch.accessor.PatientWatchDataAccessor;
import com.teamone.mobilewatch.model.Patient;
import com.teamone.mobilewatch.model.PatientReadings;
import com.teamone.mobilewatch.util.UserSettings;
import com.teamone.mobilewatch.xml.ProcessorType;
import com.teamone.mobilewatch.xml.XmlProccessorFactory;
import com.teamone.mobilewatch.xml.XmlProcessor;

/**
 * The class handles queries to web service to access the data in PatientWatch
 * database
 * 
 */
public class PatientWatchDataAccessorImpl implements PatientWatchDataAccessor {
	private static final String TAG = "PatientWatchDataAccessorImpl";

	private static PatientWatchDataAccessor instance = null;
	private HttpRequesterHelper httpRequesterHelper = null;

	/**
	 * Creates instance of the class
	 */
	private PatientWatchDataAccessorImpl() {
		httpRequesterHelper = new HttpRequesterHelper();
	}

	/**
	 * Returns instance of the class
	 */
	public static PatientWatchDataAccessor getInstance() {
		if (instance == null) {
			instance = new PatientWatchDataAccessorImpl();
		}
		return instance;
	}

	/**
	 * Returns list of all patients
	 */
	@Override
	public ArrayList<Patient> getAllPatients() throws Exception {

		String xmlResponse = httpRequesterHelper.sendPostRequest("/GetAllPatients", null);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<ArrayList<Patient>> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.PATIENT);

		ArrayList<Patient> patients = processor.process(xmlResponse);

		return patients;
	}

	/**
	 * Returns patient instance
	 * 
	 * @param patientId
	 *            - id of the patient
	 */
	@Override
	public ArrayList<Patient> getPatient(int patientId) throws Exception {

		HashMap<String, String> params = new HashMap<String, String>();
		params.put("patientId", Integer.toString(patientId));

		String xmlResponse = httpRequesterHelper.sendPostRequest("/GetPatient", params);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<ArrayList<Patient>> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.PATIENT);

		return processor.process(xmlResponse);
	}

	/**
	 * Returns patient readings records
	 * 
	 * @param patientId
	 *            - id of the patient
	 */
	@Override
	public ArrayList<PatientReadings> getPatientReadings(int patientId)
			throws Exception {

		HashMap<String, String> params = new HashMap<String, String>();
		params.put("patientId", Integer.toString(patientId));

		String xmlResponse = httpRequesterHelper.sendPostRequest("/GetPatientReadings", params);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<ArrayList<PatientReadings>> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.PATIENT_READINGS);

		return processor.process(xmlResponse);
	}

	/**
	 * Returns last patient readings record
	 * 
	 * @param patientId
	 *            - id of the patient
	 */
	@Override
	public PatientReadings getLastPatientReadings(int patientId)
			throws Exception {
		PatientReadings patientReadings = null;

		HashMap<String, String> params = new HashMap<String, String>();
		params.put("patientId", Integer.toString(patientId));

		String xmlResponse = httpRequesterHelper.sendPostRequest("/GetLastPatientReadings", params);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<ArrayList<PatientReadings>> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.PATIENT_READINGS);
		ArrayList<PatientReadings> readingsRecords = processor
				.process(xmlResponse);

		if (readingsRecords != null && readingsRecords.size() > 0) {
			patientReadings = readingsRecords.get(0); // one record expected
		}

		return patientReadings;
	}

	/**
	 * Returns state of the simulator
	 */
	@Override
	public boolean isSimulatorRunning() throws Exception {
		boolean response = false;

		String xmlResponse = httpRequesterHelper.sendPostRequest("/IsSimulatorRunning", null);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<Boolean> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.SIMULATOR_STATE);
		response = processor.process(xmlResponse);
		Log.d(TAG, "returning response:" + response);
		return response;
	}

	/**
	 * Starts simulator
	 */
	@Override
	public boolean startSimulator(int updatePeriod) throws Exception {
		boolean response = false;

		HashMap<String, String> params = new HashMap<String, String>();
		params.put("updatePeriodSec", Integer.toString(updatePeriod));

		String xmlResponse = httpRequesterHelper.sendPostRequest("/StartSimulator", params);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<Boolean> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.SIMULATOR_STATE);
		response = processor.process(xmlResponse);
		Log.d(TAG, "returning response:" + response);
		return response;
	}

	/**
	 * Stops simulator
	 */
	@Override
	public boolean stopSimulator() throws Exception {
		boolean response = false;

		String xmlResponse = httpRequesterHelper.sendPostRequest("/StopSimulator", null);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<Boolean> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.SIMULATOR_STATE);
		response = processor.process(xmlResponse);
		Log.d(TAG, "returning response:" + response);
		return response;
	}

	/**
	 * Authenticates user - simplified version for demo only
	 * 
	 * 
	 * @param userName - user name
	 * @param password - user password
	 * @return <true> if user is authenticated
	 * @throws Exception
	 */
	@Override
	public boolean authenticateUser(String userName, String password)
			throws Exception {
		boolean response = false;

		HashMap<String, String> params = new HashMap<String, String>();
		params.put("userName", userName);
		params.put("password", password);
		
		String xmlResponse = httpRequesterHelper.sendPostRequest("/AuthenticateUser", params);

		Log.d(TAG, "" + xmlResponse);
		XmlProcessor<Boolean> processor = XmlProccessorFactory
				.getProcessor(ProcessorType.SIMPLE_RESPONSE);
		response = processor.process(xmlResponse);
		Log.d(TAG, "returning response:" + response);
		return response;
	}
	
	/**
	 * HttpRequester Helper to handle webservice timeouts 
	 * when webservice is unavailable  
	 */
	private class HttpRequesterHelper{
		/**
		 * Sends post request to the default webservice, in case of connectivity issues
		 * the webservice is changed to the mirror and the request is sent to the new
		 * webservice
		 * 
		 * @param requestPath - request path appended to the webservice URI
		 * @param params - parameters of the request 
		 * @return - response string 
		 * @throws BackendException
		 */
		public String sendPostRequest(String requestPath, HashMap<String, String> params) throws BackendException{
			
			String requestUri = UserSettings.getWebServiceUri() + requestPath;
			String xmlResponse =  "";
			Log.d(TAG, "requestUri:" + requestUri);
			try{
				xmlResponse = HttpRequester.sendPostRequest(requestUri, params);
			} catch (Exception e) {
				Log.d(TAG, "Exception:" + e.getMessage());
				// retry connect using mirror web service
				UserSettings.switchWebServiceUri();				
				requestUri = UserSettings.getWebServiceUri() + requestPath;
				Log.d(TAG, "Reconnecting using:" + requestUri);
				xmlResponse = HttpRequester.sendPostRequest(requestUri, params);
			}
			
			return xmlResponse;
		}
		
	}
}
